﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Collections.Specialized;

namespace Utility
{
    public static class HttpHelper
    {
        const int bytebuff = 1024;
        const int ReadWriteTimeOut = 2 * 1000;//超时等待时间
        const int TimeOutWait = 5 * 1000;//超时等待时间
        const int MaxTryTime = 12;
        static Dictionary<string, int> TryNumDic = new Dictionary<string, int>();

        /// <summary>
        /// Http上传文件
        /// </summary>
        public static string HttpUploadFile1(string url, string path)
        {
            // 设置参数
            HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
            CookieContainer cookieContainer = new CookieContainer();
            request.CookieContainer = cookieContainer;
            request.AllowAutoRedirect = true;
            request.Method = "POST";
            string boundary = DateTime.Now.Ticks.ToString("X"); // 随机分隔线
            request.ContentType = "multipart/form-data;charset=utf-8;boundary=" + boundary;
            byte[] itemBoundaryBytes = Encoding.UTF8.GetBytes("\r\n--" + boundary + "\r\n");
            byte[] endBoundaryBytes = Encoding.UTF8.GetBytes("\r\n--" + boundary + "--\r\n");
            int pos = path.LastIndexOf("\\");
            string fileName = path.Substring(pos + 1);
            //请求头部信息 
            StringBuilder sbHeader = new StringBuilder(string.Format("Content-Disposition:form-data;name=\"file\";filename=\"{0}\"\r\nContent-Type:application/octet-stream\r\n\r\n", fileName));
            byte[] postHeaderBytes = Encoding.UTF8.GetBytes(sbHeader.ToString());
            FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);
            byte[] bArr = new byte[fs.Length];
            fs.Read(bArr, 0, bArr.Length);
            fs.Close();
            Stream postStream = request.GetRequestStream();
            postStream.Write(itemBoundaryBytes, 0, itemBoundaryBytes.Length);
            postStream.Write(postHeaderBytes, 0, postHeaderBytes.Length);
            postStream.Write(bArr, 0, bArr.Length);
            postStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);
            postStream.Close();
            //发送请求并获取相应回应数据
            HttpWebResponse response = request.GetResponse() as HttpWebResponse;
            //直到request.GetResponse()程序才开始向目标网页发送Post请求
            Stream instream = response.GetResponseStream();
            StreamReader sr = new StreamReader(instream, Encoding.UTF8);
            //返回结果网页（html）代码
            string content = sr.ReadToEnd();
            return content;
        }

        public static string MyUploader(string strFileToUpload, string strUrl, string strFileFormName, NameValueCollection querystring, CookieContainer cookies)
        {
            string postdata;
            postdata = "?";
            if (querystring != null)
            {
                foreach (string key in querystring.Keys)
                {
                    postdata += key + "=" + querystring.Get(key) + "&";
                }
            }
            //Uri uri = new Uri(strUrl + postdata);  

            Uri oUri = new Uri(strUrl + postdata);

            string strBoundary = "----------" + DateTime.Now.Ticks.ToString("x");

            // The trailing boundary string  
            byte[] boundaryBytes = Encoding.ASCII.GetBytes("\r\n--" + strBoundary + "\r\n");

            // The post message header  
            StringBuilder sb = new StringBuilder();
            sb.Append("--");
            sb.Append(strBoundary);
            sb.Append("\r\n");
            sb.Append("Content-Disposition: form-data; name=\"");
            sb.Append(strFileFormName);
            sb.Append("\"; filename=\"");
            sb.Append(Path.GetFileName(strFileToUpload));
            sb.Append("\"");
            sb.Append("\r\n");
            sb.Append("Content-Type: ");
            sb.Append("application/octet-stream");
            sb.Append("\r\n");
            sb.Append("\r\n");
            string strPostHeader = sb.ToString();
            byte[] postHeaderBytes = Encoding.UTF8.GetBytes(strPostHeader);

            // The WebRequest  
            HttpWebRequest oWebrequest = (HttpWebRequest)WebRequest.Create(oUri);

            //如果是发送HTTPS请求    
            if (strUrl.StartsWith("https", StringComparison.OrdinalIgnoreCase))
            {
                ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
                oWebrequest = WebRequest.Create(oUri) as HttpWebRequest;
                oWebrequest.ProtocolVersion = HttpVersion.Version10;
            }
            else
            {
                oWebrequest = WebRequest.Create(oUri) as HttpWebRequest;
            }

            oWebrequest.ContentType = "multipart/form-data; boundary=" + strBoundary;
            oWebrequest.Method = "POST";

            // This is important, otherwise the whole file will be read to memory anyway...  
            oWebrequest.AllowWriteStreamBuffering = false;

            // Get a FileStream and set the final properties of the WebRequest  
            FileStream oFileStream = new FileStream(strFileToUpload, FileMode.Open, FileAccess.Read);
            long length = postHeaderBytes.Length + oFileStream.Length + boundaryBytes.Length;
            oWebrequest.ContentLength = length;
            Stream oRequestStream = oWebrequest.GetRequestStream();

            // Write the post header  
            oRequestStream.Write(postHeaderBytes, 0, postHeaderBytes.Length);

            // Stream the file contents in small pieces (4096 bytes, max).  
            byte[] buffer = new Byte[checked((uint)Math.Min(4096, (int)oFileStream.Length))];
            int bytesRead = 0;
            while ((bytesRead = oFileStream.Read(buffer, 0, buffer.Length)) != 0)
                oRequestStream.Write(buffer, 0, bytesRead);
            oFileStream.Close();

            // Add the trailing boundary  
            oRequestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
            WebResponse oWResponse = oWebrequest.GetResponse();
            Stream s = oWResponse.GetResponseStream();
            StreamReader sr = new StreamReader(s);
            String sReturnString = sr.ReadToEnd();

            // Clean up  
            oFileStream.Close();
            oRequestStream.Close();
            s.Close();
            sr.Close();

            return sReturnString;
        }

        /// <summary>
        /// Http上传文件
        /// </summary>
        public static string HttpUploadFile(string path, string url)
        {
            // 设置参数
            HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
            CookieContainer cookieContainer = new CookieContainer();
            request.CookieContainer = cookieContainer;
            request.AllowAutoRedirect = true;
            request.Method = "POST";
            string boundary = DateTime.Now.Ticks.ToString("X"); // 随机分隔线
            request.ContentType = "multipart/form-data;charset=utf-8;boundary=" + boundary;
            byte[] itemBoundaryBytes = Encoding.UTF8.GetBytes("\r\n--" + boundary + "\r\n");
            byte[] endBoundaryBytes = Encoding.UTF8.GetBytes("\r\n--" + boundary + "--\r\n");
            int pos = path.LastIndexOf("\\");
            string fileName = path.Substring(pos + 1);
            //请求头部信息 
            StringBuilder sbHeader = new StringBuilder(string.Format("Content-Disposition:form-data;name=\"file\";filename=\"{0}\"\r\nContent-Type:application/octet-stream\r\n\r\n", fileName));
            byte[] postHeaderBytes = Encoding.UTF8.GetBytes(sbHeader.ToString());
            FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);
            byte[] bArr = new byte[fs.Length];
            fs.Read(bArr, 0, bArr.Length);
            fs.Close();
            Stream postStream = request.GetRequestStream();
            postStream.Write(itemBoundaryBytes, 0, itemBoundaryBytes.Length);
            postStream.Write(postHeaderBytes, 0, postHeaderBytes.Length);
            postStream.Write(bArr, 0, bArr.Length);
            postStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);
            postStream.Close();
            //发送请求并获取相应回应数据
            HttpWebResponse response = request.GetResponse() as HttpWebResponse;
            //直到request.GetResponse()程序才开始向目标网页发送Post请求
            Stream instream = response.GetResponseStream();
            StreamReader sr = new StreamReader(instream, Encoding.UTF8);
            //返回结果网页（html）代码
            string content = sr.ReadToEnd();
            return content;
        }

        public static string UploadFileEx(string uploadfile, string url,
  string fileFormName, string contenttype, NameValueCollection querystring,
  CookieContainer cookies)
        {
            if ((fileFormName == null) ||
              (fileFormName.Length == 0))
            {
                fileFormName = "file";
            }

            if ((contenttype == null) ||
              (contenttype.Length == 0))
            {
                contenttype = "application/octet-stream";
            }
            string postdata;
            postdata = "?";
            if (querystring != null)
            {
                foreach (string key in querystring.Keys)
                {
                    postdata += key + "=" + querystring.Get(key) + "&";
                }
            }
            Uri uri = new Uri(url + postdata);

            string boundary = "----------" + DateTime.Now.Ticks.ToString("x");
            HttpWebRequest webrequest = (HttpWebRequest)WebRequest.Create(uri);
            webrequest.CookieContainer = cookies;
            webrequest.ContentType = "multipart/form-data; boundary=" + boundary;
            webrequest.Method = "POST";

            // Build up the post message header  
            StringBuilder sb = new StringBuilder();
            sb.Append("--");
            sb.Append(boundary);
            sb.Append("");
            sb.Append("Content-Disposition: form-data; name=\"");
            sb.Append(fileFormName);
            sb.Append("\"; filename=\"");
            sb.Append(Path.GetFileName(uploadfile));
            sb.Append("\"");
            sb.Append("");
            sb.Append("Content-Type: ");
            sb.Append(contenttype);
            sb.Append("");
            sb.Append("");

            string postHeader = sb.ToString();
            byte[] postHeaderBytes = Encoding.UTF8.GetBytes(postHeader);

            // Build the trailing boundary string as a byte array  
            // ensuring the boundary appears on a line by itself  
            byte[] boundaryBytes =
                Encoding.ASCII.GetBytes("--" + boundary + "");

            FileStream fileStream = new FileStream(uploadfile,
                          FileMode.Open, FileAccess.Read);
            long length = postHeaderBytes.Length + fileStream.Length +
                                boundaryBytes.Length;
            webrequest.ContentLength = length;

            Stream requestStream = webrequest.GetRequestStream();

            // Write out our post header  
            requestStream.Write(postHeaderBytes, 0, postHeaderBytes.Length);

            // Write out the file contents  
            byte[] buffer = new Byte[checked((uint)Math.Min(4096,
                         (int)fileStream.Length))];
            int bytesRead = 0;
            while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
                requestStream.Write(buffer, 0, bytesRead);

            // Write out the trailing boundary  
            requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
            WebResponse responce = webrequest.GetResponse();
            Stream s = responce.GetResponseStream();
            StreamReader sr = new StreamReader(s);

            return sr.ReadToEnd();
        }

        /**/
        /// <summary> 
        /// WebClient上传文件至服务器 
        /// </summary> 
        /// <param name="fileNamePath">文件名，全路径格式</param> 
        /// <param name="uriString">服务器文件夹路径</param> 
        /// <param name="IsAutoRename">是否自动按照时间重命名</param> 
        public static void UpLoadFile(string fileNamePath, string uriString, bool IsAutoRename)
        {
            string fileName = fileNamePath.Substring(fileNamePath.LastIndexOf("\\") + 1);
            string NewFileName = fileName;
            if (IsAutoRename)
            {
                NewFileName = DateTime.Now.ToString("yyMMddhhmmss") + DateTime.Now.Millisecond.ToString() + fileNamePath.Substring(fileNamePath.LastIndexOf("."));
            }

            string fileNameExt = fileName.Substring(fileName.LastIndexOf(".") + 1);
            if (uriString.EndsWith("/") == false) uriString = uriString + "/";

            uriString = uriString + NewFileName;

            //log.AddLog(uriString, "Log"); 
            //log.AddLog(fileNamePath, "Log"); 
            /**/
            /**/
            /**/
            /// 创建WebClient实例 
            WebClient myWebClient = new WebClient();
            myWebClient.Credentials = CredentialCache.DefaultCredentials;
            // 要上传的文件 
            FileStream fs = new FileStream(fileNamePath, FileMode.Open, FileAccess.Read);
            //FileStream fs = OpenFile(); 
            BinaryReader r = new BinaryReader(fs);
            byte[] postArray = r.ReadBytes((int)fs.Length);
            Stream postStream = myWebClient.OpenWrite(uriString, "PUT");


            try
            {

                //使用UploadFile方法可以用下面的格式 
                //myWebClient.UploadFile(uriString,"PUT",fileNamePath); 


                if (postStream.CanWrite)
                {
                    postStream.Write(postArray, 0, postArray.Length);
                    postStream.Close();
                    fs.Dispose();

                }
                else
                {
                    postStream.Close();
                    fs.Dispose();

                }

            }
            catch (Exception err)
            {
                postStream.Close();
                fs.Dispose();
                //Utility.LogWriter log = new Utility.LogWriter(); 
  
                throw err;
            }
            finally
            {
                postStream.Close();
                fs.Dispose();
            }
        } 

        private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        {
            return true; //总是接受    
        }


        public static void UploadFileBinary(string localFile, string uploadUrl)
        {
            ServicePointManager.ServerCertificateValidationCallback =new RemoteCertificateValidationCallback(CheckValidationResult);//验证服务器证书回调自动验证
            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(uploadUrl);
            req.Credentials = new NetworkCredential("admin", "ehong.123");//用户名,密码
            req.PreAuthenticate = true;
            req.Method = "PUT";
            req.AllowWriteStreamBuffering = true;
            // Retrieve request stream
            Stream reqStream = req.GetRequestStream();

            // Open the local file
            FileStream rdr = new FileStream(localFile, FileMode.Open);

            // Allocate byte buffer to hold file contents
            byte[] inData = new Byte[4096];

            // loop through the local file reading each data block
            // and writing to the request stream buffer
            int bytesRead = rdr.Read(inData, 0, inData.Length);
            while (bytesRead > 0)
            {
                reqStream.Write(inData, 0, bytesRead);
                bytesRead = rdr.Read(inData, 0, inData.Length);
            }

            rdr.Close();
            reqStream.Close();

            req.GetResponse();
        }

        public static void DeleteFile(string uploadUrl)
        {
            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(uploadUrl);
            req.Credentials = new NetworkCredential("Administrator", "123456");
            req.PreAuthenticate = true;
            req.Method = "DELETE";
            //req.AllowWriteStreamBuffering = true;

            req.GetResponse();
        }

        /// <summary>
        /// 下载文件（同步）  支持断点续传
        /// </summary>
        /// <param name="url">文件url</param>
        /// <param name="savepath">本地保存路径</param>
        /// <param name="progress">下载进度（百分比）</param>
        /// <param name="reDownload">是否是重新下载</param>
        public static bool DownLoadFile(string url, string savepath, ref string message, bool reDownload = false)
        {
            //打开上次下载的文件
            long lStartPos = 0;
            FileStream fs = null;
            int progress = 0;
            message = string.Empty;
            long size = 0;

            HttpWebRequest request = null;
            try
            {
                if (!reDownload)
                {
                    size = GetFileContentLength(url);
                }

                if (File.Exists(savepath))
                {
                    fs = File.OpenWrite(savepath);
                    lStartPos = fs.Length;
                    fs.Seek(lStartPos, SeekOrigin.Current);//移动文件流中的当前指针

                    //如果已下载大小已经超过了网络文件大小,证明不是同一个文件,则删除重新下载
                    if (size < lStartPos || reDownload)
                    {
                        lStartPos = 0;
                        fs.Flush();
                        fs.Close();

                        File.Delete(savepath);
                        fs = new FileStream(savepath, FileMode.Create);
                        lStartPos = 0;
                    }
                }
                else
                {
                    string direName = Path.GetDirectoryName(savepath);
                    if (!Directory.Exists(direName))//如果不存在保存文件夹路径，新建文件夹
                    {
                        Directory.CreateDirectory(direName);
                    }

                    fs = new FileStream(savepath, FileMode.Create);
                    lStartPos = 0;
                }



                if (size != 0 && size == lStartPos)
                {
                    //下载完成
                    fs.Close();
                    return true;
                }

                request = (HttpWebRequest)WebRequest.Create(url);
                //request.ReadWriteTimeout = ReadWriteTimeOut;
                //request.Timeout = TimeOutWait;
                if (lStartPos > 0)
                    request.AddRange((int)lStartPos);//设置Range值，断点续传

                //向服务器请求，获得服务器回应数据流
                WebResponse respone = request.GetResponse();
                long totalSize = respone.ContentLength + lStartPos;
                long curSize = lStartPos;
                progress = (int)(curSize / totalSize * 100);

                Stream ns = respone.GetResponseStream();

                byte[] nbytes = new byte[bytebuff];
                int nReadSize = 0;
                nReadSize = ns.Read(nbytes, 0, bytebuff);
                curSize += nReadSize;

                while (nReadSize > 0)
                {
                    fs.Write(nbytes, 0, nReadSize);
                    nReadSize = ns.Read(nbytes, 0, bytebuff);

                    curSize += nReadSize;
                    //下载进度计算
                    if (progress < (int)((double)curSize / totalSize * 100))
                        progress = (int)((double)curSize / totalSize * 100);
                }

                fs.Flush();
                ns.Close();
                fs.Close();

                if (curSize != totalSize)//文件长度不等于下载长度，下载出错
                {
                    if (reDownload)
                    {
                        //断点续传,如果发现下载完成和服务器上的不一样,则重新下载,重新下载后还是不一样,直接异常
                        message = "文件大小不一致.错误编号[100]";
                        return false;
                    }
                    else
                    {
                        //断点续传,如果发现下载完成和服务器上的不一样,则重新下载
                        DownLoadFile(url, savepath, ref message, true);
                    }
                }
                if (request != null)
                {
                    request.Abort();
                }
            }
            catch (System.Net.WebException webEx)
            {
                message = "下载异常.";

                switch (webEx.Status)
                {
                    case WebExceptionStatus.Timeout:
                        message = "网络异常,连接超时.";
                        break;
                    case WebExceptionStatus.Success:
                        break;
                    case WebExceptionStatus.ProtocolError:
                        string fileName = Path.GetFileName(savepath);
                        message = "[" + fileName + "]下载失败.";
                        break;
                    case WebExceptionStatus.ConnectFailure:
                        message = "网络异常,连接不上服务器.";
                        break;
                }

                message += "错误编号[" + (int)webEx.Status + "]";

                return false;
            }
            catch (Exception e)
            {
                message += "下载异常.错误编号[101]";
                return false;
            }
            finally
            {
                if (request != null)
                {
                    request.Abort();
                }

                if (fs != null)
                {
                    fs.Close();
                }
            }

            return true;
        }

        /// <summary>
        /// 获取下载文件长度
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        public static long GetFileContentLength(string url)
        {
            HttpWebRequest request = null;
            try
            {
                request = (HttpWebRequest)HttpWebRequest.Create(url);
                //request.Timeout = TimeOutWait;
                //request.ReadWriteTimeout = ReadWriteTimeOut;
                //向服务器请求，获得服务器回应数据流
                WebResponse respone = request.GetResponse();
                request.Abort();
                return respone.ContentLength;
            }
            catch (Exception e)
            {
                if (request != null)
                    request.Abort();
                return 0;
            }
        }

    }
}